package com.uvnos4j.matilda.schedule.service.impl;

import cn.hutool.core.lang.Console;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.uvnos4j.matilda.commons.dto.PageParam;
import com.uvnos4j.matilda.commons.dto.QueryParam;
import com.uvnos4j.matilda.commons.exception.ServiceException;
import com.uvnos4j.matilda.commons.utils.MpUtil;
import com.uvnos4j.matilda.schedule.DynamicTaskManager;
import com.uvnos4j.matilda.schedule.domain.ScheduleTask;
import com.uvnos4j.matilda.schedule.error.ScheduleError;
import com.uvnos4j.matilda.schedule.mapper.ScheduleTaskMapper;
import com.uvnos4j.matilda.schedule.service.ScheduleTaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.Collection;
import java.util.List;

/**
 * 任务调度 service 实现
 * <p>
 * Description:任务调度 service 实现
 * </p>
 *
 * @author Guo.wl
 * @version v1.0.0
 * @see com.uvnos4j.matilda.schedule.service.impl
 * @since 2020-08-31 22:44:38
 */
@Service
@Transactional(readOnly = true)
public class ScheduleTaskServiceImpl extends ServiceImpl<ScheduleTaskMapper, ScheduleTask>
        implements ScheduleTaskService {

    @Autowired
    private DynamicTaskManager dynamicTaskManager;

    @Override
    public IPage<ScheduleTask> findPage(QueryParam param, PageParam pageParam, String orderBy) {
        initAllTask();
        String taskKey = param.getStringValue("taskKey");
        String taskDesc = param.getStringValue("taskDesc");
        String initStartFlag = param.getStringValue("initStartFlag");

        LambdaQueryWrapper<ScheduleTask> lqw = new LambdaQueryWrapper<>();
        lqw.eq(StrUtil.isNotBlank(taskKey), ScheduleTask::getTaskKey, taskKey);
        lqw.eq(StrUtil.isNotBlank(taskDesc), ScheduleTask::getTaskDesc, taskDesc);
        lqw.eq(StrUtil.isNotBlank(initStartFlag), ScheduleTask::getInitStartFlag, initStartFlag);

        Page<ScheduleTask> page = new Page<>(pageParam.getPageNum(), pageParam.getPageSize());
        page.setOrders(MpUtil.getOrderList(orderBy));

        return baseMapper.selectPage(page, lqw);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(ScheduleTask task) {
        if (hasSameTask(task.getTaskKey(), null)) {
            throw new ServiceException(ScheduleError.SCHEDULE_TASK_REPEAT);
        }
        if (task.getInitStartFlag() == 1) {
            dynamicTaskManager.startTask(task);
        }
        return baseMapper.insert(task) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(ScheduleTask task) {
        ScheduleTask before = baseMapper.selectById(task.getId());
        if (before == null) {
            throw new ServiceException(ScheduleError.SCHEDULE_TASK_NO_EXIST);
        }
        if (hasSameTask(task.getTaskKey(), task.getId())) {
            throw new ServiceException(ScheduleError.SCHEDULE_TASK_REPEAT);
        }
        if (!before.getTaskCron().equals(task.getTaskCron())) {
            task.setInitStartFlag(1);
            dynamicTaskManager.restartTask(task);
        } else {
            Integer initStartFlag = task.getInitStartFlag();
            if (before.getInitStartFlag().equals(initStartFlag)) {
                if (initStartFlag == 0) {
                    dynamicTaskManager.stopTask(task);
                } else if (initStartFlag == 1) {
                    dynamicTaskManager.startTask(task);
                }
            }
        }
        return baseMapper.updateById(task) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeByIds(Collection<? extends Serializable> idList) {
        int num = 0;
        for (Serializable id : idList) {
            ScheduleTask task = baseMapper.selectById(id);
            if (task == null) {
                throw new ServiceException(ScheduleError.SCHEDULE_TASK_NO_EXIST);
            }
            dynamicTaskManager.stopTask(task);
            baseMapper.deleteById(id);
            num++;
        }
        return num > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean start(String taskKey) {
        // 根据key数据库获取任务配置信息
        List<ScheduleTask> taskList = findByTaskKey(taskKey);
        if (taskList != null && taskList.size() > 0) {
            ScheduleTask scheduleTask = taskList.get(0);
            scheduleTask.setInitStartFlag(1);
            baseMapper.updateById(scheduleTask);
            // 启动任务
            return dynamicTaskManager.startTask(taskList.get(0));
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean stop(String taskKey) {
        List<ScheduleTask> taskList = findByTaskKey(taskKey);
        if (taskList != null && taskList.size() > 0) {
            ScheduleTask scheduleTask = taskList.get(0);
            scheduleTask.setInitStartFlag(0);
            baseMapper.updateById(scheduleTask);
            // 关闭任务
            return dynamicTaskManager.stopTask(scheduleTask);
        }
        return false;
    }

    @Override
    public boolean restart(String taskKey) {
        List<ScheduleTask> taskList = findByTaskKey(taskKey);
        if (taskList != null && taskList.size() > 0) {
            // 重启任务
            return dynamicTaskManager.restartTask(taskList.get(0));
        }
        return false;
    }

    @Override
    public void export(QueryParam param, PageParam pageParam, String orderBy, String fileDest) {

    }

    /**
     * 程序启动时初始化 ==> 启动所有正常状态的任务
     */
    @Override
    public void initAllTask() {
        List<ScheduleTask> scheduledTaskBeanList = baseMapper.getAllNeedStartTask();
        if (scheduledTaskBeanList == null || scheduledTaskBeanList.size() == 0) {
            return;
        }
        Console.log("程序启动 ==> 初始化所有任务开始 ！size={}", scheduledTaskBeanList.size());
        for (ScheduleTask scheduleTask : scheduledTaskBeanList) {
            dynamicTaskManager.startTask(scheduleTask);
        }
        Console.log("程序启动 ==> 初始化所有任务结束 ！size={}", scheduledTaskBeanList.size());

    }

    /**
     * 新增或修改时校验是否有相同任务
     *
     * @param taskKey 任务标识
     * @param id      任务ID
     * @return true含有相同任务；false不含相同任务
     */
    private boolean hasSameTask(String taskKey, Long id) {
        LambdaQueryWrapper<ScheduleTask> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ScheduleTask::getTaskKey, taskKey).ne(id != null, ScheduleTask::getId, id);
        Integer count = baseMapper.selectCount(lqw);
        return count > 0;
    }

    private List<ScheduleTask> findByTaskKey(String taskKey) {
        LambdaQueryWrapper<ScheduleTask> lqw = new LambdaQueryWrapper<>();
        lqw.eq(ScheduleTask::getTaskKey, taskKey);
        return baseMapper.selectList(lqw);
    }

}